import axios from 'axios'
import { MessageBox, Message } from 'element-ui'
import store from '@/store'
import { getToken } from '@/utils/auth'
import { formatFormData } from '@/utils'

// 全局变量对象，专门存放所有请求的cancel方法
const pendingRequest = new Map()

// 生成request的唯一的标识
const generateRequestKey = (config = {}) => {
  // 通过url，method，params，data生成唯一key，用于判断是否重复请求
  // params为get请求参数，data为post请求参数
  const { url, method } = config
  if (method === 'get') {
    // return [url, method, qs.stringify(params)].join('&')
    return [url, method].join('&')
  }
  // return [url, method, qs.stringify(data)].join('&')
  return [url, method].join('&')
}

// 将重复请求添加到pendingRequest中
const addPendingRequest = (config) => {
  const key = generateRequestKey(config)
  if (!pendingRequest.has(key)) {
    config.cancelToken = new axios.CancelToken((cancel) => {
      pendingRequest.set(key, cancel)
    })
  }
}

// 取消重复请求
const cancelRepeatRequest = (config) => {
  const key = generateRequestKey(config)
  if (pendingRequest.has(key)) {
    const cancelToken = pendingRequest.get(key)
    cancelToken() // 取消之前发送的请求
    pendingRequest.delete(key) // 请求对象中删除requestKey
  }
}

// create an axios instance

axios.defaults.baseURL = process.env.VUE_APP_BASE_API
axios.defaults.timeout = 100000

// 允许重复发送的请求
const repeatRequest = []
// request interceptor
axios.interceptors.request.use(
  (config) => {
    config.headers['AUTHORIZATION'] = getToken()
    if (config.loading) {
      store.commit('app/showLoading')
    }
    if (config.data) {
      config.data = formatFormData(config.data)
    }

    // 取消重复请求
    let canRepeat = false
    repeatRequest.forEach((item) => {
      if (config.url && config.url.includes(item)) {
        //  允许存在多个请求
        canRepeat = true
      }
    })
    if (!canRepeat) {
      // 取消重复请求
      cancelRepeatRequest(config)
      // 添加请求到队列
      addPendingRequest(config)
    }
    return config
  },
  (error) => {
    console.log(error) // for debug
    return Promise.reject(error)
  }
)

// response interceptor
axios.interceptors.response.use(
  (response) => {
    // 取消请求队列中该请求
    cancelRepeatRequest(response.config)

    if (response.config.loading) {
      store.commit('app/hideLoading')
    }

    const res = response.data
    // if the custom code is not 20000, it is judged as an error.
    if (res.code && res.code !== 200) {
      // 50008: Illegal token; 50012: Other clients logged in; 50014: Token expired;
      if (res.code === 1000) {
        // to re-login
        MessageBox.alert('登录失效,请重新登录', {
          confirmButtonText: '确定',
          type: 'warning',
          callback: (action) => {
            store.dispatch('user/resetToken').then(() => {
              location.reload()
            })
            localStorage.removeItem('feijiu_user_menu')
          }
        })
      } else {
        if (response.config.noErrorToast !== true) {
          Message({
            message: res.msg || 'Error',
            type: 'error',
            duration: 5 * 1000
          })
        }
      }
      return Promise.reject(new Error(res.msg || 'Error'))
    } else {
      return res
    }
  },
  (error) => {
    // 取消请求队列中该请求
    cancelRepeatRequest(error.config || {})

    store.commit('app/hideLoading')
    if (error.message) {
      Message({
        message: error.message,
        type: 'error',
        duration: 5 * 1000
      })
    }
    return Promise.reject(error)
  }
)

export default axios
